package com.example.myapplication.slice.slice;

import ohos.ai.asr.AsrClient;
import ohos.ai.asr.AsrIntent;
import ohos.ai.asr.AsrListener;
import ohos.ai.asr.util.AsrError;
import ohos.ai.asr.util.AsrResultKey;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.audio.AudioStreamInfo;
import ohos.utils.PacMap;
import ohos.utils.zson.ZSONObject;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static ohos.data.search.schema.PhotoItem.TAG;

public class AsrUtils {
    //采样率限定16000HZ
    private static final int VIDEO_SAMPLE_RATE = 16000;
    //VAD结束时间 默认2000ms
    private static final int VAD_END_WAIT_MS = 2000;
    //VAD起始时间 默认4800ms
    //这两参数与识别准确率有关，相关信息可百度查看，在此使用系统默认
    private static final int VAD_FRONT_WAIT_MS = 4800;
    //输入时常 20000ms
    private static final int TIMEOUT_DURATION = 20000;

    //PCM流长度仅限640或1280
    private static final int BYTES_LENGTH = 1280;
    //线程池相关参数
    private static final int CAPACITY = 6;
    private static final int ALIVE_TIME = 3;
    private static final int POOL_SIZE = 3;

    //录音线程
    private ThreadPoolExecutor poolExecutor;

    /* 自定义状态信息
     **  错误：-1
     **  初始：0
     **  init:1
     **  开始输入:2
     **  结束输入:3
     **  识别结束:5
     **  中途出识别结果:9
     **  最终识别结果：10
     */
    public int state = 0;
    //识别结果
    public String result;
    //是否开启语音识别
    //当开启时才写入PCM流
    boolean isStarted = false;

    //ASR客户端
    private AsrClient asrClient;
    //ASR监听对象
    private AsrListener listener;
    AsrIntent asrIntent;
    //音频录制工具类
    private AudioCaptureUtils audioCaptureUtils;

    public AsrUtils(Context context) {
        //实例化一个单声道，采集频率16000HZ的音频录制工具类实例
        this.audioCaptureUtils = new AudioCaptureUtils(AudioStreamInfo.ChannelMask.CHANNEL_IN_MONO, VIDEO_SAMPLE_RATE);
        //初始化降噪音效
        this.audioCaptureUtils.init("com.panda_coder.liedetector");
        //结果值设为空
        this.result = "";
        //给录音控件初始化一个新的线程池
        poolExecutor = new ThreadPoolExecutor(
                POOL_SIZE,
                POOL_SIZE,
                ALIVE_TIME,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(CAPACITY),
                new ThreadPoolExecutor.DiscardOldestPolicy());

        if (asrIntent == null) {
            asrIntent = new AsrIntent();
            //设置音频来源为PCM流
            //此处也可设置为文件
            asrIntent.setAudioSourceType(AsrIntent.AsrAudioSrcType.ASR_SRC_TYPE_PCM);
            asrIntent.setVadEndWaitMs(VAD_END_WAIT_MS);
            asrIntent.setVadFrontWaitMs(VAD_FRONT_WAIT_MS);
            asrIntent.setTimeoutThresholdMs(TIMEOUT_DURATION);
        }

        if (asrClient == null) {
            //实例化AsrClient
            asrClient = AsrClient.createAsrClient(context).orElse(null);
        }
        if (listener == null) {
            //实例化MyAsrListener
            listener = new MyAsrListener();
            //初始化AsrClient
            this.asrClient.init(asrIntent, listener);
        }

    }


    private static final HiLogLabel TAG = new HiLogLabel(0x12345, 0x12345, "YourLogTag");
    //够建一个实现AsrListener接口的类MyAsrListener
    class MyAsrListener implements AsrListener {

        @Override
        public void onInit(PacMap pacMap) {
            HiLog.info(TAG, "====== init");
            state = 1;
        }

        @Override
        public void onBeginningOfSpeech() {
            state = 2;
        }

        @Override
        public void onRmsChanged(float v) {

        }

        @Override
        public void onBufferReceived(byte[] bytes) {

        }

        @Override
        public void onEndOfSpeech() {
            state = 3;
        }

        @Override
        public void onError(int i) {
            state = -1;
            if (i == AsrError.ERROR_SPEECH_TIMEOUT) {
                //当超时时重新监听
                asrClient.startListening(asrIntent);
            } else {
                HiLog.info(TAG, "======error code:" + i);
                asrClient.stopListening();
            }
        }

        //注意与onIntermediateResults获取结果值的区别
        //pacMap.getString(AsrResultKey.RESULTS_RECOGNITION);
        @Override
        public void onResults(PacMap pacMap) {
            state = 10;
            //获取最终结果
            //{"result":[{"confidence":0,"ori_word":"你 好 ","pinyin":"NI3 HAO3 ","word":"你好。"}]}
            String results = pacMap.getString(AsrResultKey.RESULTS_RECOGNITION);
            ZSONObject zsonObject = ZSONObject.stringToZSON(results);
            ZSONObject infoObject;
            if (zsonObject.getZSONArray("result").getZSONObject(0) instanceof ZSONObject) {
                infoObject = zsonObject.getZSONArray("result").getZSONObject(0);
                String resultWord = infoObject.getString("ori_word").replace(" ", "");
                result += resultWord;
            }
        }

        //中途识别结果
        //pacMap.getString(AsrResultKey.RESULTS_INTERMEDIATE)
        @Override
        public void onIntermediateResults(PacMap pacMap) {
            state = 9;
//            String result = pacMap.getString(AsrResultKey.RESULTS_INTERMEDIATE);
//            if (result == null)
//                return;
//            ZSONObject zsonObject = ZSONObject.stringToZSON(result);
//            ZSONObject infoObject;
//            if (zsonObject.getZSONArray("result").getZSONObject(0) instanceof ZSONObject) {
//                infoObject = zsonObject.getZSONArray("result").getZSONObject(0);
//                String resultWord = infoObject.getString("ori_word").replace(" ", "");
//                HiLog.info(TAG, "=========== 9 " + resultWord);
//            }
        }


        @Override
        public void onEnd() {
            state = 5;
            //当还在录音时，重新监听
            if (isStarted)
                asrClient.startListening(asrIntent);
        }

        @Override
        public void onEvent(int i, PacMap pacMap) {

        }

        @Override
        public void onAudioStart() {
            state = 2;

        }

        @Override
        public void onAudioEnd() {
            state = 3;
        }
    }

    public void start() {
        if (!this.isStarted) {
            this.isStarted = true;
            asrClient.startListening(asrIntent);
            poolExecutor.submit(new AudioCaptureRunnable());
        }
    }

    public void stop() {
        this.isStarted = false;
        asrClient.stopListening();
        audioCaptureUtils.stop();
    }

    //音频录制的线程
    private class AudioCaptureRunnable implements Runnable {
        @Override
        public void run() {
            byte[] buffers = new byte[BYTES_LENGTH];
            //开启录音
            audioCaptureUtils.start();
            while (isStarted) {
                //读取录音的PCM流
                int ret = audioCaptureUtils.read(buffers, 0, BYTES_LENGTH);
                if (ret <= 0) {
                    HiLog.error(TAG, "======Error read data");
                } else {
                    //将录音的PCM流写入到语音识别服务中
                    //若buffer的长度不为1280或640时，则需要手动处理成1280或640
                    asrClient.writePcm(buffers, BYTES_LENGTH);
                }
            }
        }
    }

    //识别结果是通过 listener 的回调获取的结果，所以我们在处理时是将结果赋值给 result，通过 getResult 或 getResultAndClear 函数获取结果。
    public String getResult() {
        return result;
    }

    public String getResultAndClear() {
        if (this.result == "")
            return "";
        String results = getResult();
        this.result = "";
        return results;
    }

}
